home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / smtp / smtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  13.7 KB  |  623 lines

  1. /* smtp: as invoked by qmgr to deliver smtp stuff*/
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/smtp/RCS/smtp.c,v 6.0 1991/12/18 20:12:19 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/smtp/RCS/smtp.c,v 6.0 1991/12/18 20:12:19 jpo Rel $
  9.  *
  10.  * $Log: smtp.c,v $
  11.  * Revision 6.0  1991/12/18  20:12:19  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "head.h"
  19. #include "chan.h"
  20. #include "prm.h"
  21. #include "q.h"
  22. #include "dr.h"
  23. #include "qmgr.h"
  24. #include <pwd.h>
  25. #include "sys.file.h"
  26. #include <signal.h>
  27. #include <isode/internet.h>
  28. #ifdef SYS5
  29. #include <sys/time.h>
  30. #endif
  31.  
  32. extern  char    *quedfldir;
  33. extern void    rd_end(), chan_init(), err_abrt(), timer_start(), timer_end();
  34. FILE            *msg_fp;
  35. CHAN            *mychan;
  36. char            *this_msg;
  37. int        smtpport = 0;
  38.  
  39. extern struct sm_rstruct {              /* save last reply obtained */
  40.     int     sm_rval;                /* rp.h value for reply */
  41.     int     sm_rlen;                /* current lengh of reply string */
  42.     char    sm_rgot;                /* true, if have a reply */
  43.     char    sm_rstr[LINESIZE];      /* human-oriented reply text */
  44. } sm_rp;
  45. #define smtp_error(def) (sm_rp.sm_rgot ? sm_rp.sm_rstr : (def))
  46.  
  47. extern int data_bytes;
  48. extern time_t time();
  49.  
  50.  
  51. #define SM_RTIME        15              /* Time allowed for a RSET command */
  52. #define SM_TTIME        180             /* Time allowed for a block of text */
  53.  
  54.  
  55. static struct type_Qmgr_DeliveryStatus *process();
  56. static void dirinit();
  57. static int chaninit();
  58. static int endproc ();
  59. static int dotext ();
  60. static int copy ();
  61.  
  62.  
  63. /* ---------------------  Begin  Routines  -------------------------------- */
  64.  
  65.  
  66.  
  67.  
  68. main (argc, argv)
  69. int     argc;
  70. char    **argv;
  71. {
  72.     char    *p;
  73.     int    opt;
  74.     extern char *optarg;
  75.  
  76.     if ((p = rindex (argv[0], '/')) != NULLCP)
  77.         p ++;
  78.     if (p == NULLCP || *p == NULL)
  79.         p = argv[0];
  80.  
  81.     chan_init (p);   /* init the channel - and find out who we are */
  82.  
  83.     while ((opt = getopt (argc, argv, "p:")) != EOF) {
  84.         switch (opt) {
  85.             case 'p':
  86.             smtpport = htons (atoi (optarg));
  87.             break;
  88.  
  89.             default:
  90.             PP_LOG (LLOG_EXCEPTIONS,
  91.                 ("Bad argument -%c", opt));
  92.             break;
  93.         }
  94.     }
  95.  
  96.  
  97.     dirinit();              /* get to the right directory */
  98.     (void) signal (SIGPIPE, SIG_IGN);
  99. #ifdef PP_DEBUG
  100.     if (argc > 1 && strcmp (argv[1], "debug") == 0)
  101.         debug_channel_control (argc, argv, chaninit, process, endproc);
  102.     else
  103. #endif
  104.         channel_control (argc, argv, chaninit, process, endproc);
  105.     exit (0);
  106. }
  107.  
  108.  
  109.  
  110. static int chaninit (arg)
  111. struct type_Qmgr_Channel *arg;
  112. {
  113.     char    *p = qb2str (arg);
  114.  
  115.     if ((mychan = ch_nm2struct (p)) == (CHAN *)0)
  116.         err_abrt (RP_PARM, "Channel '%s' not known", p);
  117.  
  118.     rename_log(p); 
  119.     sm_init (mychan);
  120.     PP_NOTICE (("starting %s (%s)", mychan -> ch_name, mychan -> ch_show));
  121.     free (p);
  122.     return OK;
  123. }
  124.  
  125. char    *cur_host;
  126. char    *open_host;
  127. int    open_state;        /* defines meaning of open_host */
  128. #define STATE_INITIAL     0
  129. #define STATE_OPEN        1
  130. #define STATE_BAD_HOST    2
  131. #define STATE_TIMED_OUT    3
  132. char    *sender;
  133. char    *formatdir;
  134.  
  135. static int endproc ()
  136. {
  137.     if (cur_host)
  138.         sm_nclose (OK);
  139. }
  140.  
  141. static struct type_Qmgr_DeliveryStatus *process (arg)
  142. struct type_Qmgr_ProcMsg *arg;
  143. {
  144.     struct prm_vars prm;
  145.     struct type_Qmgr_UserList *up;
  146.     Q_struct        Qstruct, *qp = &Qstruct;
  147.     int     retval;
  148.     ADDR    *ap,
  149.         *ad_sendr = NULLADDR,
  150.         *ad_recip = NULLADDR,
  151.         *alp = NULLADDR,
  152.         *ad_list = NULLADDR;
  153.     int     ad_count;
  154.  
  155.     if (this_msg) free (this_msg);
  156.  
  157.     this_msg = qb2str (arg -> qid);
  158.  
  159.     bzero ((char *)&prm, sizeof prm);
  160.     bzero ((char *)qp, sizeof *qp);
  161.  
  162.     (void) delivery_init (arg -> users);
  163.  
  164.     retval = rd_msg (this_msg, &prm, qp, &ad_sendr, &ad_recip, &ad_count);
  165.  
  166.     if (rp_isbad (retval)) {
  167.         PP_LOG (LLOG_EXCEPTIONS, ("rd_msg err: %s", this_msg));
  168.         return delivery_setallstate (int_Qmgr_status_messageFailure,
  169.                          "Can't read message");
  170.     }
  171.  
  172.     sender = ad_sendr -> ad_r822adr;
  173.  
  174.     for (ap = ad_recip; ap; ap = ap -> ad_next) {
  175.         for (up = arg ->users; up; up = up -> next) {
  176.             if (up -> RecipientId -> parm != ap -> ad_no)
  177.                 continue;
  178.  
  179.             switch (chan_acheck (ap, mychan,
  180.                          ad_list == NULLADDR, &cur_host)) {
  181.                 default:
  182.                 case NOTOK:
  183.                 continue;
  184.  
  185.                 case OK:
  186.                 break;
  187.             }
  188.             break;
  189.         }
  190.         if (up == NULL)
  191.             continue;
  192.  
  193.         if (ad_list == NULLADDR)
  194.             ad_list = alp = (ADDR *) calloc (1, sizeof *alp);
  195.         else {
  196.             alp -> ad_next = (ADDR *) calloc (1, sizeof *alp);
  197.             alp = alp -> ad_next;
  198.         }
  199.         *alp = *ap;
  200.         alp -> ad_next = NULLADDR;
  201.     }
  202.  
  203.     if (ad_list == NULLADDR) {
  204.         PP_LOG (LLOG_EXCEPTIONS, ("No recipients in user list"));
  205.         rd_end ();
  206.         q_free (qp);
  207.         return deliverystate;
  208.     }
  209.  
  210.     PP_NOTICE (("processing msg %s to %s", this_msg, cur_host));
  211.  
  212.     deliver (ad_list, qp);
  213.  
  214.     q_free (qp);
  215.     rd_end();
  216.  
  217.     return deliverystate;
  218. }
  219.  
  220. static void dirinit()       /* Change into pp queue space */
  221. {
  222.     if (chdir (quedfldir) < 0)
  223.         err_abrt (RP_LIO, "Unable to change directory to '%s'",
  224.                         quedfldir);
  225. }
  226.  
  227. deliver (ad_list, qp)
  228. ADDR    *ad_list;
  229. Q_struct *qp;
  230. {
  231.     ADDR    *ap;
  232.     int     naddrs;
  233.     char    buf [LINESIZE];
  234.  
  235.     PP_TRACE (("deliver ()"));
  236.  
  237.  
  238.     if (lexequ (cur_host, open_host) != 0) { 
  239.                     /* Brand new host */
  240.  
  241.         if (open_host != NULLCP) {
  242.             free (open_host);    
  243.             if (open_state == STATE_OPEN) 
  244.                 sm_nclose (OK);
  245.         }
  246.         open_host = strdup (cur_host);
  247.  
  248.         switch (sm_nopen (cur_host, buf))
  249.         {
  250.             case RP_OK:
  251.                 open_state = STATE_OPEN;
  252.                 break;
  253.             case RP_NO:
  254.                 open_state = STATE_BAD_HOST;
  255.                 break;
  256.             default:
  257.                 open_state = STATE_TIMED_OUT;
  258.                 break;
  259.         }
  260.     }
  261.  
  262.     switch (open_state)
  263.     {
  264.         case STATE_OPEN:
  265.             break;        /* just carry on */
  266.         case STATE_BAD_HOST:
  267.             PP_NOTICE ((buf));
  268.             set_all_dr (qp, ad_list, this_msg,
  269.                  DRR_UNABLE_TO_TRANSFER,
  270.                  DRD_UNRECOGNISED_OR,
  271.                  buf);
  272.             if (rp_isgood(wr_q2dr (qp, this_msg)))
  273.                 (void) delivery_setall (int_Qmgr_status_negativeDR);
  274.             return;
  275.         case STATE_TIMED_OUT:
  276.             PP_NOTICE (("Connection failed to '%s': %s",
  277.                     cur_host, buf));
  278.             (void) delivery_setallstate
  279.                 (int_Qmgr_status_mtaFailure,
  280.                  buf);
  281.             return;
  282.     }
  283.  
  284.     naddrs = 0;
  285.  
  286.     if (do_sender (sender) == NOTOK) {
  287.         if (rp_isbad(wr_q2dr (qp, this_msg)))
  288.             delivery_resetDRs(int_Qmgr_status_messageFailure);
  289.         return;
  290.     }
  291.  
  292.     for (ap = ad_list; ap; ap = ap -> ad_next) {
  293.         switch (do_recip (ap, qp) ){
  294.             case OK:
  295.             naddrs ++;
  296.             break;
  297.  
  298.             case NOTOK:
  299.             break;
  300.  
  301.             default:
  302.             return;
  303.         }
  304.     }
  305.  
  306.     if (naddrs == 0) {
  307.         (void) reset ();
  308.         if (rp_isbad(wr_q2dr (qp, this_msg)))
  309.             delivery_resetDRs (int_Qmgr_status_messageFailure);
  310.         PP_NOTICE ((">>> Message %s transfered to no recipients",
  311.                 this_msg, naddrs));
  312.         return;
  313.     }
  314.  
  315.     if (dotext (qp, ad_list, naddrs) == NOTOK) {
  316.         if (rp_isbad(wr_q2dr (qp, this_msg)))
  317.             delivery_resetDRs(int_Qmgr_status_messageFailure);
  318.         return;
  319.     }
  320.  
  321.     for (ap = ad_list; ap; ap = ap -> ad_next) {
  322.         if (ap -> ad_resp) {
  323.             if (ap -> ad_usrreq == AD_USR_CONFIRM ||
  324.                 ap -> ad_mtarreq == AD_MTA_CONFIRM ||
  325.                 ap -> ad_mtarreq == AD_MTA_AUDIT_CONFIRM) {
  326.                 set_1dr (qp, ap -> ad_no, this_msg,
  327.                      DRR_NO_REASON, -1, NULLCP);
  328.                 delivery_set (ap -> ad_no,
  329.                           int_Qmgr_status_positiveDR);
  330.             }
  331.             else {
  332.                 (void) wr_ad_status (ap, AD_STAT_DONE);
  333.                 (void) wr_stat (ap, qp, this_msg, data_bytes);
  334.                 delivery_set (ap -> ad_no,
  335.                           int_Qmgr_status_success);
  336.             }
  337.         }
  338.     }
  339.     if (rp_isbad(wr_q2dr (qp, this_msg)))
  340.         delivery_resetDRs(int_Qmgr_status_messageFailure);
  341.     PP_NOTICE ((">>> Message %s transfered to %d recipients",
  342.             this_msg, naddrs));
  343. }       
  344.  
  345. do_recip (ap, qp)
  346. ADDR    *ap;
  347. Q_struct *qp;
  348. {
  349.     int     retval;
  350.     char    errbuf[BUFSIZ];
  351.  
  352.     PP_NOTICE (("Recipient %s", ap -> ad_r822adr));
  353.  
  354.     if (rp_isbad (retval = sm_wto (ap ->ad_r822adr))) {
  355.         switch (retval) {
  356.             case RP_DHST:
  357.             PP_LOG (LLOG_EXCEPTIONS, ("Host died"));
  358.             (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
  359.                         "Host died");
  360.             return DONE;
  361.  
  362.             case RP_AOK:
  363.             ap -> ad_resp = 1;
  364.             return OK;
  365.  
  366.             case RP_AGN:
  367.             (void) delivery_setstate (ap -> ad_no,
  368.                       int_Qmgr_status_messageFailure,
  369.                          smtp_error ("temporary failure"));
  370.             PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s",
  371.                           smtp_error ("cause not known")));
  372.             ap -> ad_resp = 0;
  373.             return NOTOK;
  374.  
  375.             case RP_USER:
  376.             (void) delivery_set (ap -> ad_no,
  377.                       int_Qmgr_status_negativeDR);
  378.             (void) sprintf (errbuf,
  379.                     "MTA '%s' gives error message %s",
  380.                     cur_host, smtp_error ("problem with user"));
  381.             PP_LOG (LLOG_EXCEPTIONS, ("User error: %s", errbuf));
  382.             set_1dr (qp, ap -> ad_no, this_msg,
  383.                  DRR_UNABLE_TO_TRANSFER,
  384.                  DRD_UNRECOGNISED_OR, 
  385.                  errbuf);
  386.             ap -> ad_resp = 0;
  387.             return NOTOK;
  388.  
  389.             case RP_PARM:
  390.             ap -> ad_resp = 0;
  391.             PP_LOG (LLOG_EXCEPTIONS, ("Parameter problem: %s",
  392.                           smtp_error("bad paramter")));
  393.             (void) delivery_setstate (ap -> ad_no,
  394.                       int_Qmgr_status_messageFailure,
  395.                          smtp_error ("bad parameter"));
  396.             return NOTOK;
  397.  
  398.             case RP_RPLY:
  399.             default:
  400.             PP_LOG (LLOG_EXCEPTIONS, ("Message failure: %s",
  401.                           smtp_error ("bad reply")));
  402.             (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  403.                         smtp_error ("bad reply"));
  404.             (void) reset ();
  405.             return DONE;
  406.         }
  407.     }
  408.     return OK;
  409. }
  410.  
  411. do_sender (sndr)
  412. char    *sndr;
  413. {
  414.     int     retval;
  415.  
  416.     PP_NOTICE (("sender %s", sndr));
  417.  
  418.     if (rp_isbad (retval = sm_wfrom (sndr))) {
  419.         switch (retval) {
  420.             case RP_DHST:
  421.             PP_LOG (LLOG_EXCEPTIONS, ("Host connection died"));
  422.             (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
  423.                         "host connection failed");
  424.             sm_nclose (NOTOK);
  425.             return NOTOK;
  426.  
  427.             case RP_PARM:
  428.             PP_LOG (LLOG_EXCEPTIONS, ("Parameter problem: %s",
  429.                           smtp_error("bad param")));
  430.             (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
  431.                         smtp_error ("bad param"));
  432.             sm_nclose (NOTOK);
  433.             return NOTOK;
  434.  
  435.             case RP_AGN:
  436.             (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  437.                         smtp_error ("temp error"));
  438.             PP_LOG (LLOG_EXCEPTIONS, ("Temporary error: %s",
  439.                           smtp_error ("temp error")));
  440.             (void) reset ();
  441.             return NOTOK;
  442.  
  443.             case RP_OK:
  444.             break;
  445.  
  446.             default:
  447.             PP_LOG (LLOG_EXCEPTIONS, ("Protocol error: %s",
  448.                           smtp_error("")));
  449.             (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
  450.                         smtp_error ("protocol problem"));
  451.             sm_nclose (NOTOK);
  452.             return NOTOK;
  453.         }
  454.     }
  455.     return OK;
  456. }
  457.  
  458.  
  459. static int dotext (qp, ap, naddrs)
  460. Q_struct *qp;
  461. ADDR    *ap;
  462. int     naddrs;
  463. {
  464.     extern  FILE    *sm_wfp;
  465.     int     retval;
  466.     char    filename[MAXPATHLENGTH];
  467.     struct timeval data_time;
  468.     int    first = 1;
  469.     char    errbuf[BUFSIZ];
  470.  
  471.     if (qid2dir (this_msg, ap, TRUE, &formatdir) == NOTOK) {
  472.         PP_LOG (LLOG_EXCEPTIONS, ("Can't locate message %s",
  473.                       this_msg));
  474.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  475.                     "Cant find message");
  476.         (void) reset ();
  477.         return NOTOK;
  478.     }
  479.  
  480.  
  481.     if (rp_isbad (retval = msg_rinit (formatdir))) {
  482.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  483.                     "Can't read message");
  484.         reset ();
  485.         return NOTOK;
  486.     }
  487.  
  488.     if (rp_isbad (retval = sm_wrdata ())) {
  489.         switch (retval) {
  490.             case RP_DHST:
  491.             PP_LOG (LLOG_EXCEPTIONS, ("Host connection died"));
  492.             (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
  493.                         "Connection died");
  494.  
  495.             break;
  496.  
  497.             case RP_NDEL:
  498.             (void) delivery_set (ap -> ad_no,
  499.                          int_Qmgr_status_negativeDR);
  500.             (void) sprintf (errbuf,
  501.                     "DATA transfer to host failed permanently: %s",
  502.                     smtp_error ("reason unknown"));
  503.             PP_LOG (LLOG_EXCEPTIONS, ("DATA error: %s", errbuf));
  504.             set_1dr (qp, ap -> ad_no, this_msg,
  505.                  DRR_UNABLE_TO_TRANSFER,
  506.                  DRD_UNRECOGNISED_OR, 
  507.                  errbuf);
  508.             break;
  509.  
  510.             default:
  511.  
  512.  
  513.             (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  514.                              smtp_error ("dead host?"));
  515.  
  516.             break;
  517.         }
  518.         sm_nclose (NOTOK);
  519.         return NOTOK;
  520.     }
  521.  
  522.     data_bytes = 0;
  523.     timer_start (&data_time);
  524.  
  525.     while ((retval = msg_rfile (filename)) == RP_OK) {
  526.         if (rp_isbad (copy (filename))) {
  527.             (void) delivery_setallstate(int_Qmgr_status_mtaAndMessageFailure,
  528.                            "Can't transfer data");
  529.             sm_nclose (NOTOK);
  530.             return NOTOK;
  531.         }
  532.         if (first) {
  533.             sm_wstm ("\n", 1);
  534.             first = 0;
  535.         }
  536.     }
  537.     if (rp_isbad (retval)) {
  538.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  539.                          "Message transfer failed");
  540.         sm_nclose (NOTOK);
  541.         return NOTOK;
  542.     }
  543.  
  544.     if (rp_isbad (sm_wstm (NULLCP, 0))) {
  545.         (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  546.                     "Bad temination of data");
  547.         sm_nclose (NOTOK);
  548.         return NOTOK;
  549.     }
  550.  
  551.     if (rp_isbad (retval = sm_wrdot (naddrs))) {
  552.         switch (retval) {
  553.             case RP_DHST:
  554.             PP_LOG (LLOG_EXCEPTIONS, ("Host connection died"));
  555.             (void) delivery_setallstate (int_Qmgr_status_mtaAndMessageFailure,
  556.                         "Connection died");
  557.  
  558.             break;
  559.  
  560.             case RP_NDEL:
  561.             (void) delivery_setall (int_Qmgr_status_negativeDR);
  562.             (void) sprintf (errbuf,
  563.                     "DATA transfer to host failed permanently");
  564.             PP_LOG (LLOG_EXCEPTIONS, ("DATA error: %s", errbuf));
  565.             set_1dr (qp, ap -> ad_no, this_msg,
  566.                  DRR_UNABLE_TO_TRANSFER,
  567.                  DRD_UNRECOGNISED_OR, 
  568.                  errbuf);
  569.             break;
  570.  
  571.             default:
  572.             PP_LOG (LLOG_EXCEPTIONS, ("Temporary failure: %s",
  573.                           smtp_error ("bad data")));
  574.             (void) delivery_setallstate (int_Qmgr_status_messageFailure,
  575.                         smtp_error ("bad data"));
  576.             break;
  577.         }
  578.         return NOTOK;
  579.     }
  580.     timer_end (&data_time, data_bytes, "Data Transfered");
  581.     msg_rend();
  582.  
  583.     return OK;
  584. }
  585.  
  586. static int copy (fname)
  587. char    *fname;
  588. {
  589.     FILE    *ifp;
  590.     char    buf[BUFSIZ];
  591.     int     n, retval = RP_OK;
  592.  
  593.     if ((ifp = fopen (fname,"r")) == NULL) {
  594.         PP_LOG (LLOG_EXCEPTIONS, ("Can't read file '%s'", fname));
  595.         return RP_FOPN;
  596.     }
  597.  
  598.     while ((n = fread (buf, sizeof (char), sizeof (buf), ifp)) > 0)
  599.         if (rp_isbad (retval = sm_wstm (buf, n)))
  600.             break;
  601.     (void) fclose (ifp);
  602.     return retval;
  603. }
  604.  
  605. reset ()
  606. {
  607.     int     retval;
  608.  
  609.     if (rp_isbad (retval = sm_cmd ("RSET", SM_RTIME))) {
  610.         switch (retval) {
  611.             default:
  612.             (void) delivery_setallstate (int_Qmgr_status_mtaFailure,
  613.                         smtp_error ("reset failed"));
  614.             sm_nclose (NOTOK);
  615.             return NOTOK;
  616.  
  617.             case RP_OK:
  618.             break;
  619.         }
  620.     }
  621.     return OK;
  622. }
  623.